﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace GenCallDB
{
	class Program
	{
		public const int LicenseStatusIndex = 5;
		public const int LicenseIdIndex = 1;
		public const int ZipCodeIndex = 18;
		public const int CallsignIndex = 4;
		public const int NameIndex = 8;
		public const int LocationIndex = 15;

		public const string LicenseStatusActive = "A";

		public const int MaxLinesPerFile = 70000;
		public const string PreviousLicenseFile = "lastrun.txt";

		static void Main( string[] args )
		{
			string
				outputFileName = null,
				input;
			string[]
				prefixes;
			string[]
				values;
			int
				fileIndex = 0,
				countPerFile = 0,
				count;
			bool
				isLocal;
			ActiveLicenses
				activeLicenses = new ActiveLicenses();
			Dictionary<string, LicenseDetails>
				previousLicenses = new Dictionary<string, LicenseDetails>();
			LinkedList<LicenseDetails>
				newLicenses = new LinkedList<LicenseDetails>(),
				updatedLicenses = new LinkedList<LicenseDetails>(),
				currentLicenses = new LinkedList<LicenseDetails>();
			LicenseDetails
				previousDetails,
				details;
			StreamWriter
				writer = null;

			Console.WriteLine( "Enter comma-separated ZIP prefixes to extract:" );
			input = Console.ReadLine();

			if ( !string.IsNullOrWhiteSpace( input ) )
			{
				prefixes = input.Split( ',', ' ' ).Where( p => !string.IsNullOrWhiteSpace( p ) ).ToArray();

				if ( File.Exists( PreviousLicenseFile ) )
				{
					Console.WriteLine( "Opening {0}...", PreviousLicenseFile );
					using ( StreamReader reader = File.OpenText( PreviousLicenseFile ) )
					{
						while ( ( input = reader.ReadLine() ) != null )
						{
							previousDetails = new LicenseDetails( input );
							previousLicenses[ previousDetails.RosterId ] = previousDetails;
						}
					}
				}

				Console.WriteLine( "Opening HD..." );
				try
				{
					using ( StreamReader reader = File.OpenText( "HD.dat" ) )
					{
						count = 0;
						while ( ( input = reader.ReadLine() ) != null )
						{
							if ( !string.IsNullOrWhiteSpace( input ) )
							{
								++count;
								values = input.Split( '|' );
								if ( values[ LicenseStatusIndex ] == LicenseStatusActive )
								{
									activeLicenses[ int.Parse( values[ LicenseIdIndex ] ) ] = true;
								}
							}
						}
					}

					Console.WriteLine( "Read {0} entries from HD", count );
				}
				catch
				{
					Console.WriteLine( "Error reading from HD" );
					return;
				}

				Console.WriteLine( "Opening EN..." );
				try
				{
					using ( StreamReader reader = File.OpenText( "EN.dat" ) )
					{
						while ( ( input = reader.ReadLine() ) != null )
						{
							if ( !string.IsNullOrWhiteSpace( input ) )
							{
								values = input.ToUpper().Replace( "'", string.Empty ).Split( '|' );
								if ( activeLicenses[ int.Parse( values[ LicenseIdIndex ] ) ] )
								{
									if ( !string.IsNullOrWhiteSpace( values[ CallsignIndex ] ) && !string.IsNullOrWhiteSpace( values[ NameIndex ] ) )
									{
										isLocal = false;
										foreach ( string item in prefixes )
										{
											if ( values[ ZipCodeIndex ].StartsWith( item ) )
											{
												isLocal = true;
												break;
											}
										}
										details = new LicenseDetails( values, isLocal );
										if ( previousLicenses.TryGetValue( details.RosterId, out previousDetails ) )
										{
											if ( !details.Equals( previousDetails ) )
												updatedLicenses.AddLast( details );
											else
												currentLicenses.AddLast( details );
											previousLicenses.Remove( details.RosterId );
										}
										else
											newLicenses.AddLast( details );
									}
								}
							}
						}
					}
				}
				catch
				{
					Console.WriteLine( "Error reading from EN" );
					return;
				}

				foreach ( LicenseDetails item in newLicenses )
				{
					if ( writer == null )
					{
						outputFileName = string.Format( "valid_callsigns{0}.sql", fileIndex++ );
						countPerFile = 0;
						writer = File.CreateText( outputFileName );
					}

					item.WriteInsertSql( writer );

					if ( ++countPerFile == MaxLinesPerFile )
					{
						Console.WriteLine( "Wrote {0} lines to file {1}", countPerFile, outputFileName );
						writer.Dispose();
						writer = null;
					}
				}

				foreach ( LicenseDetails item in updatedLicenses )
				{
					if ( writer == null )
					{
						outputFileName = string.Format( "valid_callsigns{0}.sql", fileIndex++ );
						countPerFile = 0;
						writer = File.CreateText( outputFileName );
					}

					item.WriteUpdateSql( writer );

					if ( ++countPerFile == MaxLinesPerFile )
					{
						Console.WriteLine( "Wrote {0} lines to file {1}", countPerFile, outputFileName );
						writer.Dispose();
						writer = null;
					}
				}

				foreach ( LicenseDetails item in previousLicenses.Values )
				{
					if ( writer == null )
					{
						outputFileName = string.Format( "valid_callsigns{0}.sql", fileIndex++ );
						countPerFile = 0;
						writer = File.CreateText( outputFileName );
					}

					item.WriteDeleteSql( writer );

					if ( ++countPerFile == MaxLinesPerFile )
					{
						Console.WriteLine( "Wrote {0} lines to file {1}", countPerFile, outputFileName );
						writer.Dispose();
						writer = null;
					}
				}

				if ( writer != null )
				{
					Console.WriteLine( "Wrote {0} lines to file {1}", countPerFile, outputFileName );
					writer.Dispose();
					writer = null;
				}

				Console.WriteLine( "Wrote {0} total entries to {1} files, {2} local entries", newLicenses.Count + updatedLicenses.Count +
					previousLicenses.Count, fileIndex, newLicenses.Where( l => l.IsLocal ).Count() + updatedLicenses.Where( l => l.IsLocal ).Count() +
					currentLicenses.Where( l => l.IsLocal ).Count() );

				Console.WriteLine( "Writing {0}...", PreviousLicenseFile );
				writer = File.CreateText( PreviousLicenseFile );
				foreach ( LicenseDetails item in currentLicenses )
				{
					writer.WriteLine( item.ToString() );
				}
				foreach ( LicenseDetails item in newLicenses )
				{
					writer.WriteLine( item.ToString() );
				}
				foreach ( LicenseDetails item in updatedLicenses )
				{
					writer.WriteLine( item.ToString() );
				}
				writer.Dispose();

				Console.WriteLine( "Processing complete, press Enter to exit..." );
				Console.ReadLine();
			}
		}
	}
}
